package hashTableArray

import (
	"crypto/sha512"
	"errors"
)

const (
	Deleted      = iota //数据已经被删除  0
	MintableSize = 100  //哈希表的大小
	legimate     = iota //已经存在的合法数据 1
	Empty        = iota //数据为空 2
)

// 简单的hash函数
func MySHA(str interface{}) int {
	var HashVal int = 0

	var chars []byte
	if str1, ok := str.(string); ok {
		chars = []byte(str1)
	}

	for _, v := range chars {
		HashVal = (HashVal<<78 | 123&1235 ^ 139) + int(v)
	}

	return HashVal % MintableSize
}

// SHA256
func MySHA256(str interface{}) int {

	str1, _ := str.(string)

	shaObj := sha512.New()
	shaObj.Write([]byte(str1))

	mybytes := shaObj.Sum(nil)

	var Hashvar int = 0
	for _, v := range mybytes {
		Hashvar = (Hashvar<<3 | 123&1235 ^ 139) + int(v) //哈希算法
	}
	return Hashvar % MintableSize
}

type HashFunc func(str interface{}) int // 函数指针

type HashEntry struct {
	data interface{} //数据
	kind int
}

type HasHTable struct {
	tableSize int          // //哈希表的大小
	theCells  []*HashEntry // 数组每个元素指向哈希结构
	hashFunc  HashFunc
}

func NewHashTable(size int, hash HashFunc) (*HasHTable, error) {
	if size < MintableSize {
		return nil, errors.New("哈希表太小")
	}

	if hash == nil {
		return nil, errors.New("没有哈希函数")
	}

	hashTable := new(HasHTable)
	hashTable.tableSize = size
	hashTable.theCells = make([]*HashEntry, size)
	hashTable.hashFunc = hash

	for i := 0; i < hashTable.tableSize; i++ {
		hashTable.theCells[i] = new(HashEntry)
		hashTable.theCells[i].data = nil
		hashTable.theCells[i].kind = Empty
	}

	return hashTable, nil
}

//查找
func (ht *HasHTable) Find(data interface{}) int {
	var collid int = 0

	curpos := ht.hashFunc(data)
	if ht.theCells[curpos].kind != Empty && ht.theCells[curpos].data != data {
		collid += 1
		curpos := 2*curpos - 1 //平方探测

		if curpos > ht.tableSize {
			curpos -= ht.tableSize
		}

	}

	return curpos
}

func (ht *HasHTable) Insert(data interface{}) {
	cur := ht.Find(data) //查找数据的位置
	entry := ht.theCells[cur]

	if entry.kind != legimate {
		entry.kind = legimate
		entry.data = data
	}

}

//
func (ht *HasHTable) GetValue(index int) interface{} {
	if index > ht.tableSize {
		return nil
	}

	entry := ht.theCells[index]

	if entry.kind == legimate {
		return entry.data
	} else {
		return nil
	}

}
